#!/usr/bin/perl

######################################################################
package Swignition::uF::XFN;
######################################################################

use Swignition::Export;
use Swignition::GenericParser::Utils;
use Swignition::MagicString;
use XML::LibXML qw(:all);
use strict;

sub consume
{
	my $page        = shift;
	my $pageURL     = $page->uri;
	my $pageSubject = $page->{RDF}->{$pageURL};
	my $version;
	
	if ($page->{Profiles}->{'http://gmpg.org/xfn/11'}
	||  $page->{Profiles}->{'http://purl.org/uF/2008/03/'})
	{
		$version = 11;
	}
	elsif ($page->{Profiles}->{'http://gmpg.org/xfn/1'})
	{
		$version = 10;
	}
	elsif (!$page->{options}->{uf_strict_profiles})
	{
		$version = 11;
	}
	elsif (! $page->{Profiles}->{'http://xen.adactio.com/'})
	{
		return;
	}
		
	my %R = (
		'contact'       => ':',
		'acquaintance'  => 'K:',
		'friend'        => 'K:',
		'met'           => 'SK:',
		'co-worker'     => 'S:',
		'colleague'     => 'S:',
		'co-resident'   => 'SKT:',
		'neighbor'      => 'S:',
		'child'         => 'I:http://vocab.sindice.com/xfn#parent',
		'parent'        => 'I:http://vocab.sindice.com/xfn#child',
		'sibling'       => 'S:',
		'spouse'        => 'SK:',
		'kin'           => 'S:',
		'muse'          => ':',
		'crush'         => 'K:',
		'date'          => 'SK:',
		'sweetheart'    => 'SK:',
		'me'            => 'S:'
	);
	
	if ($version < 11)
	{
		delete $R{'contact'};
		delete $R{'kin'};
		delete $R{'me'};
	}
	
	if ($page->{Profiles}->{'http://xen.adactio.com/'})
	{
		$R{'nemesis'}    = 'SKE:';
		$R{'enemy'}      = 'KE:';
		$R{'nuisance'}   = 'KE:';
		$R{'evil-twin'}  = 'SE:';
		$R{'rival'}      = 'KE:';
		$R{'fury'}       = 'E:';
		$R{'creep'}      = 'E:';
	}

	my $regexp = join '|', (keys %R);
	$regexp = "(^|\\s)($regexp)(\\s|\$)";
	
	my ($needToMergeSubjectA, $needToMergeSubjectB);
	
	my $representative = findSubject($page->{RDF},
		firstOf($pageSubject,
			'http://purl.org/uF/hCard/terms/representative',
			'http://xmlns.com/foaf/0.1/primaryTopic',
			'http://xmlns.com/foaf/0.1/topic'));
	unless ($representative)
	{
		$representative = Swignition::RDFModel::Subject->new(
			Swignition::GenericParser::Utils::BNodeURI(
				$page->{DOM}->documentElement,
				'RepresentativeContact'
			)
		);
		$representative->addVal('http://www.w3.org/1999/02/22-rdf-syntax-ns#type',
			Swignition::RDFModel::Value->new('http://xmlns.com/foaf/0.1/Person', 1));
		$representative->addVal('http://xmlns.com/foaf/0.1/page',
			Swignition::RDFModel::Value->new($pageURL, 1));
		$needToMergeSubjectA = 1;
	}
	
	my @links = $page->{DOM}->getElementsByTagName('link');
	push @links, $page->{DOM}->getElementsByTagName('a');
	push @links, $page->{DOM}->getElementsByTagName('area');

	foreach my $link (@links)
	{
		next unless ($link->getAttribute('rel') =~ /$regexp/i
			|| $link->getAttribute('rev') =~ /$regexp/i);
		my $href = $page->uri($link->getAttribute('href'));
		my $needToMergeObject;
		$needToMergeSubjectB = 1;

		my $friendPage = Swignition::RDFModel::Subject->new(
			$page->uri($link->getAttribute('href')));

		# XFN to FOAF: Find Object of link.
		#
		# 1. If the link element is a descendant of an element with class="vcard"
		# which is not the representative hCard for the page, then this hCard
		# is taken to represent the person who is the object of the relationship.
		my $linkxp = $link->getAttribute('_xpath');
		my $bestlength = 99_999;
		my $best;
		my $friend;
		foreach my $hcard (@{$page->{uF}->{hCard}})
		{
			my $hcxp = $hcard->{_dom}->getAttribute('_xpath');
			
			if ((substr($linkxp, 0, length $hcxp) eq $hcxp)
			&&  (length $hcxp < $bestlength))
			{
				$bestlength = length $hcxp;
				$best = $hcard;
			}
		}
		$friend = findSubject($page->{RDF}, $best->uri)
			if ($best);
		
		# 2. If a non-representative hCard exists on the page with a UID property
		# which is identical to the target of the link element, then this hCard is
		# taken to represent the object of the relationship.
		$friend = findSubject($page->{RDF}, 'urn:x-contact-uid:'.$href)
			unless ($friend);
		
		# 4. If no hCard representing the object of the relationship has been
		# found, then the object is represented by the following triples (note
		# that foaf:name is the link text)
		unless ($friend)
		{
			my $string = STRINGIFY($link);
			$string = $link->getAttribute('title') unless ($string);
			
			$friend = Swignition::RDFModel::Subject->new(
				Swignition::GenericParser::Utils::BNodeURI($link, 'Friend') );
			$friend->addVal('http://www.w3.org/1999/02/22-rdf-syntax-ns#type',
				Swignition::RDFModel::Value->new('http://xmlns.com/foaf/0.1/Person', 1));
			$friend->addVal('http://xmlns.com/foaf/0.1/name',
				Swignition::RDFModel::Value->new($string));

			if ($href =~ /^mailto\:/i)
			{
				$friend->addVal('http://xmlns.com/foaf/0.1/mbox',
					Swignition::RDFModel::Value->new($href, 1));
			}
			elsif ($href =~ /^urn\:sha1\:([a-f0-9]+)$/i)
			{
				$friend->addVal('http://xmlns.com/foaf/0.1/mbox_sha1sum',
					Swignition::RDFModel::Value->new($1, 1));
			}
			elsif ($link->getAttribute('type') =~ /^image\//i)
			{
				$friend->addVal('http://xmlns.com/foaf/0.1/img',
					Swignition::RDFModel::Value->new($1, 1));
			}
			else
			{
				$friend->addVal('http://xmlns.com/foaf/0.1/page',
					Swignition::RDFModel::Value->new($href, 1));
			}
			
			$needToMergeObject = 1;
		}
		
		if (($link->getAttribute('rel').$link->getAttribute('rev')) =~ /\b(me)\b/i)
		{
			if ($href =~ /^mailto\:/i)
			{
				$representative->addVal('http://xmlns.com/foaf/0.1/mbox',
					Swignition::RDFModel::Value->new($href, 1));
			}
			elsif ($href =~ /^urn\:sha1\:([a-f0-9]+)$/i)
			{
				$representative->addVal('http://xmlns.com/foaf/0.1/mbox_sha1sum',
					Swignition::RDFModel::Value->new($1, 1));
			}
			elsif ($link->getAttribute('type') =~ /^image\//i)
			{
				$representative->addVal('http://xmlns.com/foaf/0.1/img',
					Swignition::RDFModel::Value->new($1, 1));
			}
			else
			{
				$representative->addVal('http://xmlns.com/foaf/0.1/page',
					Swignition::RDFModel::Value->new($href, 1));
			}
			
			$pageSubject->addVal('http://vocab.sindice.com/xfn#mePage',
				Swignition::RDFModel::Value->new($friendPage->uri,1))
				if ($link->getAttribute('rel') =~ /\b(me)\b/i);
				
			$friendPage->addVal('http://vocab.sindice.com/xfn#mePage', 
				Swignition::RDFModel::Value->new($pageSubject->uri,1))
				if ($link->getAttribute('rev') =~ /\b(me)\b/i);

			# Awesome Googly stuff.
			my $SGNM = Swignition::uF::getSGNM;
			if ($SGNM)
			{
				my $sgn = $SGNM->graph_node_from_url($href);
				if ($sgn =~ /^sgn:/)
				{
					$friend->addUri($sgn);
	
					foreach my $linktype (qw(profile rss atom foaf photo blog openid content addfriend))
					{
						my $predicate = 'http://buzzword.org.uk/rdf/personal-link-types#'.$linktype;
						$predicate = 'http://xmlns.com/foaf/0.1/openid' if ($linktype eq 'openid');
						$predicate = 'http://xmlns.com/foaf/0.1/weblog' if ($linktype eq 'blog');
						$predicate = 'http://xmlns.com/foaf/0.1/depiction' if ($linktype eq 'photo');
					
						my $u = $SGNM->graph_node_to_url($sgn, $linktype);
						$representative->addVal($predicate,
							Swignition::RDFModel::Value->new($u, 1))
							if ($u);
					}
				}
			}
			
			# Skip the rest of the code. rel=me is exclusive of the rest of XFN.
			next;
		}

		# Awesome Googly stuff.
		my $SGNM = Swignition::uF::getSGNM;
		if ($SGNM)
		{
			my $sgn = $SGNM->graph_node_from_url($href);
			if ($sgn =~ /^sgn:/)
			{
				$friend->addUri($sgn);

				foreach my $linktype (qw(profile rss atom foaf photo blog openid content addfriend))
				{
					my $predicate = 'http://buzzword.org.uk/rdf/personal-link-types#'.$linktype;
					$predicate = 'http://xmlns.com/foaf/0.1/openid' if ($linktype eq 'openid');
					$predicate = 'http://xmlns.com/foaf/0.1/weblog' if ($linktype eq 'blog');
					$predicate = 'http://xmlns.com/foaf/0.1/depiction' if ($linktype eq 'photo');
				
					my $u = $SGNM->graph_node_to_url($sgn, $linktype);
					$friend->addVal($predicate,
						Swignition::RDFModel::Value->new($u, 1))
						if ($u);
				}
			}
		}
		
		# Rel - non rel=me values
		my $rel = lc($link->getAttribute('rel'));
		$rel =~ s/(^\s+|\s+$)//g;
		$rel =~ s/\s+/ /g;
		my @rel = split / /, $rel;
		foreach my $rel (@rel)
		{
			next unless ($rel =~ /$regexp/);
			
			push @{ $page->{'uF'}->{'XFN'}->{lc($rel)} }, $friendPage->uri;

			my $ns = ($R{$rel} =~ /E/) 
				? 'http://buzzword.org.uk/rdf/xen#' 
				: 'http://vocab.sindice.com/xfn#';
			
			$representative->addVal("$ns$rel",
				Swignition::RDFModel::Value->new($friend->uri,1));
			$representative->addVal('http://xmlns.com/foaf/0.1/knows',
				Swignition::RDFModel::Value->new($friend->uri,1))
				if ($R{$rel} =~ /K/);
			$friend->addVal('http://xmlns.com/foaf/0.1/knows',
				Swignition::RDFModel::Value->new($representative->uri,1))
				if ($R{$rel} =~ /K/);
			$friend->addVal("$ns$rel",
				Swignition::RDFModel::Value->new($representative->uri,1))
				if ($R{$rel} =~ /S/);
			$friend->addVal($1,
				Swignition::RDFModel::Value->new($representative->uri,1))
				if ($R{$rel} =~ /I\:(.*)$/);
				
			$pageSubject->addVal($ns.$rel.'-hyperlink',
				Swignition::RDFModel::Value->new($friendPage->uri,1))
		}

		# Rev - non rev=me values
		my $rev = lc($link->getAttribute('rev'));
		$rev =~ s/(^\s+|\s+$)//g;
		$rev =~ s/\s+/ /g;
		my @rev = split / /, $rev;
		foreach my $rev (@rev)
		{
			next unless ($rev =~ /$regexp/);

			push @{ $page->{'uF'}->{'XFN'}->{lc($1)} }, $friendPage->uri
				if ($R{$rev} =~ /I\:(.*)$/);
			
			my $ns = ($R{$rev} =~ /E/) 
				? 'http://buzzword.org.uk/rdf/xen#' 
				: 'http://vocab.sindice.com/xfn#';
				
			$friend->addVal("$ns$rev",
				Swignition::RDFModel::Value->new($representative->uri,1));
			$friend->addVal('http://xmlns.com/foaf/0.1/knows',
				Swignition::RDFModel::Value->new($representative->uri,1));
			$representative->addVal('http://xmlns.com/foaf/0.1/knows',
				Swignition::RDFModel::Value->new($friend->uri, 1));
			$representative->addVal("$ns$rev",
				Swignition::RDFModel::Value->new($friend->uri,1))
				if ($R{$rev} =~ /^S/);
			$representative->addVal($1,
				Swignition::RDFModel::Value->new($friend->uri,1))
				if ($R{$rev} =~ /I\:(.*)$/);

			$friendPage->addVal($ns.$rel.'-hyperlink',
				Swignition::RDFModel::Value->new($pageSubject->uri,1))
		}
		
		$page->mergeSubject($friend)
			if ($needToMergeObject);
		$page->mergeSubject($friendPage)
			if ($needToMergeObject);
	}

	if ($needToMergeSubjectA && $needToMergeSubjectB)
	{
		$page->mergeSubject($representative);
		$pageSubject->addVal('http://purl.org/uF/hCard/terms/representative',
			Swignition::RDFModel::Value->new($representative->uri, 1));
	}
		
#	$page->mergeNS('xfn',     'http://gmpg.org/xfn/11#',         'XHTML Friends Network');
#	$page->mergeNS('xen',     'http://xen.adactio.com/#',        'XHTML Enemies Network');
	$page->mergeNS('xfn',     'http://vocab.sindice.com/xfn#',   'XFN in RDF');
	$page->mergeNS('xen',     'http://buzzword.org.uk/rdf/xen#', 'XEN in RDF');
	$page->mergeNS('hcterms', 'http://purl.org/uF/hCard/terms/', 'hCard Terms');

}

1;
